/*-------------------------------------------------------------------------
 *
 * plperl_system.h
 *	  引入 Perl 的系统头文件。
 *
 * 我们将其分离为一个单独的头文件，以精确控制 "system_header" pragma 的作用域。这里不应放置任何特定于 Postgres 的声明。
 * 然而，我们确实包含了一些旨在防止我们代码与 Perl 之间的冲突的内容。
 *
 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
 * Portions Copyright (c) 1995, Regents of the University of California
 *
 * src/pl/plperl/plperl_system.h
 */

#ifndef PL_PERL_SYSTEM_H
#define PL_PERL_SYSTEM_H

/*
 * 更新版本的perl头文件在我们的首选编译器标志下会触发很多警告
 * （至少已知-Wdeclaration-after-statement，-Wshadow=compatible-local存在问题）。如果支持的话，system_header
 * pragma可以隐藏这一文件其余部分的警告。
 */
#ifdef HAVE_PRAGMA_GCC_SYSTEM_HEADER
#pragma GCC system_header
#endif

/* 阻止perl头文件在Windows上劫持stdio和其他内容 */
#ifdef WIN32
#define WIN32IO_IS_STDIO
#endif							/* WIN32 */

/*
 * 提供一个满足gcc的PERL_UNUSED_DECL值 - perl自身提供的似乎不行。
 */
#define PERL_UNUSED_DECL pg_attribute_unused()

/*
 * 有时perl会小心翼翼地干扰我们的*printf宏。
 * 所以我们在这里取消定义它们，并在它完成它的肮脏工作后重新定义。
 */
#undef vsnprintf
#undef snprintf
#undef vsprintf
#undef sprintf
#undef vfprintf
#undef fprintf
#undef vprintf
#undef printf

/*
 * Perl也会干扰"_"宏。
 */
#undef _

/*
 * ActivePerl 5.18及更高版本是MinGW构建的，它们的头文件使用GCC的
 * __inline__。转换为MSVC可识别的东西。此外，perl.h有时会定义isnan，
 * 因此在这里取消定义它，并在perl.h没有定义时再放回定义。
 */
#ifdef _MSC_VER
#define __inline__ inline
#ifdef isnan
#undef isnan
#endif
/* 适用于使用MSVC和Strawberry Perl >= 5.30的解决方法。 */
#define __builtin_expect(expr, val) (expr)
#endif

/*
 * 关于bool，PostgreSQL和Perl可能使用或不使用stdbool.h，
 * 这取决于配置。如果两个都同意，事情相对无害。
 * 如果不同，情况就复杂了。 如果PostgreSQL使用但Perl不使用，在这里定义
 * HAS_BOOL，以便Perl不重新定义bool；这避免了编译器的警告。 如果PostgreSQL不使用但Perl使用，
 * 我们需要在包含Perl头文件后取消定义bool；见下文。
 */
#ifdef PG_USE_STDBOOL
#define HAS_BOOL 1
#endif

/*
 * 获取基本的Perl API。我们使用PERL_NO_GET_CONTEXT模式，以便我们的代码
 * 可以编译与MULTIPLICITY Perl构建，而不需要包含XSUB.h。
 */
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"

/*
 * 我们只想在.xs文件中包含XSUB.h，因为在某些平台上，它会不必要地重新定义很多libc函数。
 * 但它必须出现在ppport.h之前，所以使用一个#define标志在这里控制包含。
 */
#ifdef PG_NEED_PERL_XSUB_H
/*
 * 在Windows上，win32_port.h为很多这些相同的函数定义了宏。
 * 为了避免在XSUB.h重新定义它们时出现编译器警告，#undef我们的版本。
 */
#ifdef WIN32
#undef accept
#undef bind
#undef connect
#undef fopen
#undef fstat
#undef kill
#undef listen
#undef lseek
#undef lstat
#undef mkdir
#undef open
#undef putenv
#undef recv
#undef rename
#undef select
#undef send
#undef socket
#undef stat
#undef unlink
#endif

#include "XSUB.h"
#endif

/* 恢复我们的*printf宏...这必须与src/include/port.h匹配 */
#ifdef vsnprintf
#undef vsnprintf
#endif
#ifdef snprintf
#undef snprintf
#endif
#ifdef vsprintf
#undef vsprintf
#endif
#ifdef sprintf
#undef sprintf
#endif
#ifdef vfprintf
#undef vfprintf
#endif
#ifdef fprintf
#undef fprintf
#endif
#ifdef vprintf
#undef vprintf
#endif
#ifdef printf
#undef printf
#endif

#define vsnprintf		pg_vsnprintf
#define snprintf		pg_snprintf
#define vsprintf		pg_vsprintf
#define sprintf			pg_sprintf
#define vfprintf		pg_vfprintf
#define fprintf			pg_fprintf
#define vprintf			pg_vprintf
#define printf(...)		pg_printf(__VA_ARGS__)

/*
 * 也恢复"_"；但是与核心代码只将其设置为gettext()不同，
 * 使其成为dgettext()，以便在可加载模块中会发生正确的事情（如果它们已正确设置TEXTDOMAIN）。
 * 注意，我们不能在这里仅设置TEXTDOMAIN，因为此文件被比PL/Perl自身更多的扩展使用。
 */
#undef _
#define _(x) dgettext(TEXTDOMAIN, x)

/* 如果需要，恢复isnan的定义 */
#ifdef _MSC_VER
#ifndef isnan
#define isnan(x) _isnan(x)
#endif
#endif

/* perl版本和平台移植性 */
#include "ppport.h"

/*
 * perl可能已经包含了stdbool.h。如果我们之前也包含了（见c.h），
 * 那就没问题。如果没有，我们可能是出于某种原因拒绝了它。
 * 在这种情况下，取消定义bool并继续使用我们自己的bool。
 * （注意，stdbool.h将bool定义为宏，但我们自己的替换是typedef，
 * 所以取消定义使我们的再次可见）。
 */
#ifndef PG_USE_STDBOOL
#ifdef bool
#undef bool
#endif
#endif

/* 如果缺少 HeUTF8，就补充它 - 不幸的是，ppport.h 不提供它 */
#ifndef HeUTF8
#define HeUTF8(he)			   ((HeKLEN(he) == HEf_SVKEY) ?			   \
								SvUTF8(HeKEY_sv(he)) :				   \
								(U32)HeKUTF8(he))
#endif

/* 如果缺少 GvCV_set，就补充它 - 不幸的是，ppport.h 不提供它 */
#ifndef GvCV_set
#define GvCV_set(gv, cv)		(GvCV(gv) = cv)
#endif

/* Perl 5.19.4 将数组索引从 I32 更改为 SSize_t */
#if PERL_BCDVERSION >= 0x5019004
#define AV_SIZE_MAX SSize_t_MAX
#else
#define AV_SIZE_MAX I32_MAX
#endif

#endif							/* PL_PERL_SYSTEM_H */
